#ifndef _DICTIONARY_H_
#define _DICTIONARY_H_

#include "./container.h"

#include <map>

namespace Holders {

	class InvalidEntryException : public Exception {
	protected:
		string access_entry;

	public:
		InvalidEntryException( const string &message, const string &accessed_label )
			: Exception( message ), access_entry(accessed_label) {
#ifdef ALLOW_EXCEPT
			cout << (*this) << endl;
#endif
		};
		InvalidEntryException( const InvalidEntryException &original )
			: Exception( original ), access_entry(original.access_entry) {
#ifdef ALLOW_EXCEPT
			cout << (*this) << endl;
#endif
		};
		~InvalidEntryException(){
			Exception::~Exception();
		};

		inline string getEntry() const {
			return access_entry;
		};

		// --- Writeable ---
		virtual bool filePrint( FILE *parq = stdin ) const {
			return false;
		};

		virtual inline string toS() const {
			return Exception::toS() + "\nAccessing entry " + access_entry + ".";
		};
		// --- Classificable ---

		static inline string ClassName() {
			return "InvalidEntryException";
		};

		virtual inline string className() const {
			return ClassName();
		};

	};

	template< class Type >
		class Dictionary: public Container {
		private:
			map< string, Type > *match_list;

		public:

			typedef typename map< string, Type >::iterator Iter;

			Dictionary() : match_list(NULL) {
				match_list = new map< string, Type >();
			}
			Dictionary( const Dictionary<Type> &original ) : match_list(NULL) {
				match_list = new map< string, Type >();
				copy( original );
			};
			virtual ~Dictionary() {
				if( match_list != NULL ) {
					match_list->clear();
					delete match_list;
					match_list = NULL;
				}
			}

			inline void copy( const Dictionary<Type> &original ){
				for( Iter i = original.match_list->begin(); i != original.match_list->end(); ++i )
					this->match_list->insert( *i );
			}

			inline void insert( const string &name, const Type &obj ){
				match_list->insert( make_pair( name, obj ) );
			};

			inline void insert( const pair<string,Type> &obj ){
				match_list->insert( obj );
			};

			inline Type at( const string &label ) const {
				return (*this)[label];
			};

			inline usint size() const {
				return match_list->size();
			};

			inline Iter begin() const {
				return match_list->begin();
			};

			inline Iter end() const {
				return match_list->end();
			};

			inline Dictionary<Type>& operator, ( const pair<string,Type> &obj ){
				insert( obj );
				return (*this);
			};

			inline Type& operator [] ( const string &label ) const {
				Iter i = match_list->find( label );
				if( i == match_list->end() )
					throw InvalidEntryException( "This label couldn't be found in this Dictionary object.", label );
				return i->second;
			};

			bool operator == ( const Dictionary<Type> &obj ) const {
				if( this->size() != obj.size() )
					return false;
				Iter i1 = begin(); Iter i2 = obj.begin();
				for( usint i = 0; i < this->size(); ++i )
					if( (*(i1++)) != (*(i2++)) )
						return false;
				return true;
			};

			inline bool operator != ( const Dictionary<Type> &obj ) const {
				return ! ( (*this) == obj );
			}

			inline Dictionary<Type>& operator = ( const Dictionary<Type> &obj ) {
				match_list->clear();
				return (*this) += obj;
			};

			inline Dictionary<Type>& operator += ( const Dictionary<Type> &obj ) {
				for( Iter i = obj.match_list->begin(); i != obj.match_list->end(); ++i )
					insert( make_pair( i->first, i->second ) );
				return (*this);
			};

			inline Dictionary<Type> operator + ( const Dictionary<Type> &obj ) const {
				Dictionary result;
				return ( ( result += (*this) ) += obj );
			};

			// --- Writeable ---
			virtual bool filePrint( FILE *parq = stdin ) const {
				return false;
			};

			virtual inline string toS() const {
				string result = "[ ";
				for( Iter i = this->match_list->begin(); i != this->match_list->end(); ++i )
					result += string("{ ") + i->first + ", " + i->second + " } ";
				return result + "]";
			};

			// --- Classificable ---

			static inline string ClassName() {
				return "Array";
			};

			virtual inline string className() const {
				return ClassName();
			};

		};

};

#endif // _DICTIONARY_H_

//	dic.mapa->insert( std::pair<string,int>("palavra",1) );
//	dic.mapa->insert( make_pair("palavra",2) );
//	dic.mapa->insert( make_pair("palavra",1) );

//	if( dic.mapa->find("palavra") != dic.mapa->end() )
//		cout << dic.mapa->at("palavra") << endl;
